package com.cuijq.virwallet.service;

import com.cuijq.virwallet.exception.NoSufficientBalanceException;
import com.cuijq.virwallet.repository.VirtualWalletRepository;
import com.cuijq.virwallet.repository.VirtualWalletTransactionRepository;
import com.cuijq.virwallet.repository.entity.VirtualWalletEntity;
import com.cuijq.virwallet.repository.entity.VirtualWalletTransactionEntity;
import com.cuijq.virwallet.service.bo.VirtualWalletBo;
import com.cuijq.virwallet.walletenum.Status;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

@Service
public class VirtualWalletService {

    @Autowired
    private VirtualWalletRepository walletRepo;
    @Autowired
    private VirtualWalletTransactionRepository transactionRepo;

    public VirtualWalletBo getVirtualWallet(Long walletId) {
        VirtualWalletEntity walletEntity = walletRepo.getWalletEntity(walletId);
        VirtualWalletBo walletBo = convert(walletEntity);
        return walletBo;
    }


    public BigDecimal getBalance(Long walletId) {
        return walletRepo.getBalance(walletId);
    }

    public void debit(Long walletId, BigDecimal amount) throws NoSufficientBalanceException {
        VirtualWalletEntity walletEntity = walletRepo.getWalletEntity(walletId);
        BigDecimal balance = walletEntity.getBalance();
        if (balance.compareTo(amount) < 0) {
            throw new NoSufficientBalanceException("...");
        }
        walletRepo.updateBalance(walletId, balance.subtract(amount));
    }

    public void credit(Long walletId, BigDecimal amount) {
        VirtualWalletEntity walletEntity = walletRepo.getWalletEntity(walletId);
        BigDecimal balance = walletEntity.getBalance();
        walletRepo.updateBalance(walletId, balance.add(amount));
    }

    public void transfer(Long fromWalletId, Long toWalletId, BigDecimal amount) {
        VirtualWalletTransactionEntity transactionEntity = new VirtualWalletTransactionEntity();
        transactionEntity.setAmount(amount);
        transactionEntity.setCreateTime(System.currentTimeMillis());
        transactionEntity.setFromWalletId(fromWalletId);
        transactionEntity.setToWalletId(toWalletId);
        transactionEntity.setStatus(Status.TO_BE_EXECUTED);
        Long transactionId = transactionRepo.saveTransaction(transactionEntity);
        try {
            debit(fromWalletId, amount);
            credit(toWalletId, amount);
        } catch (Exception | NoSufficientBalanceException e) {
            transactionRepo.updateStatus(transactionId, Status.FAILED);
            e.printStackTrace();
        }
        transactionRepo.updateStatus(transactionId, Status.EXECUTED);
    }

    private VirtualWalletBo convert(VirtualWalletEntity walletEntity) {
        VirtualWalletBo virtualWalletBo = new VirtualWalletBo();
        BeanUtils.copyProperties(walletEntity,virtualWalletBo);
        return virtualWalletBo;
    }

    public List<VirtualWalletEntity> findAll() {
        return  walletRepo.findAll();
    }

    public void save(VirtualWalletEntity virtualWalletEntity) {
        walletRepo.save(virtualWalletEntity);
    }

    public Optional<VirtualWalletEntity> findOne(Example<VirtualWalletEntity> example) {
       return walletRepo.findOne(example);
    }

    public void deleteById(Long id) {
        walletRepo.deleteById(id);
    }
}

